
import GeographicEntiryScheme from './GeographicEntiryScheme'
import GridEnum from './GridEnum'
import CustomTile from './CustomTile'

const LevelCount = 10;
const  r_0 = 6378137.0;

//高度域编码每级字符范围（进制）
const _grids = [2, 64, 8, 2, 16, 16, 2, 8, 8, 8, 8] ;

//高度域每级编码字符数
const _codeCount = [1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1];
const _xyCodeCount = [ 1, 3, 2, 1, 2, 2, 1, 2, 2, 2, 2 ];


//高度域每级网格高度差
const _deltaHeight = [40075020, 445280, 55660, 27830, 1850, 123.69, 61.84, 7.73, 0.97, 0.121, 0.015];


const _scheme=new GeographicEntiryScheme(GridEnum.BEIDOUGRID);

function BeiDouCode(){
   
}

BeiDouCode.code=function(carto,level){
  
    var txy=_scheme.positionToTileXY(carto,0,new Cesium.Cartesian2());
    var customTile=new CustomTile({
        x:txy.x,
        y:txy.y,
        level:0,
        tilingScheme:_scheme
    })
  
    _scheme.codeTile(customTile);
    if(level==0)
        return customTile;
    var parentTile=customTile;
    for(var i=1;i<=level;i++){
         txy=_scheme.positionToTileXY(carto,i,new Cesium.Cartesian2());
         customTile=new CustomTile({
            x:txy.x,
            y:txy.y,
            level:i,
            tilingScheme:_scheme
        })
        customTile._parent=parentTile;
      
        _scheme.codeTile(customTile);
        parentTile=customTile;
    }

    var h_code = GetOneHightsCode(carto.height,level);
    var cursor_2d = 0;
            var cursor_h = 0;
            var posId_3d="";
            var posId_2d=customTile._codeStr;
            for (var i = 0; i <= level; i++)
            {
                //2d
                posId_3d += posId_2d.slice(cursor_2d, cursor_2d+_xyCodeCount[i]);
                cursor_2d += _xyCodeCount[i];
                //h
             
                
                posId_3d += h_code.slice(cursor_h,cursor_h + _codeCount[i]);
                cursor_h += _codeCount[i];
            }

            parentTile._codeStr=posId_3d;

    return parentTile;
   
}

BeiDouCode.test=function(){
    const carto=Cesium.Cartographic.fromDegrees(120.27531249999998,31.57940972222222,11.595);
    var customTile=BeiDouCode.code(carto,7);
    console.log(customTile);
}

//////////////private function/////////////////////
function GetGridsNumberOfH( h)
{
    var n = 0;
    var theta = Math.PI / (2048 * 3600 * 180);
    var theta_0 = Math.PI / 180;
    
    n = Math.floor((Math.PI * (Cesium.Math.logBase((h + r_0) / r_0, 1 + theta_0))) / (180 * theta));
    return n;
}
function GetBitsValueOfInt( origanalValue,  offset,  len)
{
    var value = origanalValue >> offset;
    var str = "";
    for (var i = 0; i < len; i++)
    {
        var temp = 1 << i;
        str += (value & temp) == temp ? "1" : "0";
    }
    return str;
}
function DecimalToArbitrarySystem( decimalNumber,  radix)
{
    const  BitsInLong = 64;
    const  Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

 
    if (decimalNumber == 0)
        return "0";

    var index = BitsInLong - 1;
    var currentNumber = Math.abs(decimalNumber);
    var charArray = new Array(BitsInLong);

    while (currentNumber != 0)
    {
        var remainder = (currentNumber % radix);
        charArray[index--] = Digits[remainder];
        currentNumber =parseInt(currentNumber / radix) ;
    }

   // var result = new String(charArray, index + 1, BitsInLong - index - 1);
   var result=charArray.slice(index + 1,BitsInLong+1);
    if (decimalNumber < 0)
    {
        result = "-" + result;
    }

    return result;
}

function DecimalTo64System( decimalNumber)
{
    var result = "";
    const  BitsInLong = 128;
    const  radix = 64;

    if (decimalNumber == 0)
        return "0";

    var index = BitsInLong - 1;
    var currentNumber = Math.abs(decimalNumber);
    var charArray = new Array(BitsInLong);

    while (currentNumber != 0)
    {
        var remainder = currentNumber % radix;
        //charArray[index--] = Convert.ToChar(remainder);
        var aStr='A'.charCodeAt();
        aStr += remainder;
        rowStr=String.fromCharCode(aStr);
        charArray[index--] = rowStr;
        currentNumber = currentNumber / radix;
    }
    for (var i = index + 1; i < BitsInLong; i++)
    {
        result += charArray[i];
    }
    if (decimalNumber < 0)
    {
        result = "-" + result;
    }

    return result;
}
       
function GetOneHightsCode( h,  l)
{
    var _codeBits = new Array(_codeCount.length);
    var n = GetGridsNumberOfH(h);

    var temp_n = 32;

    for (var i = 0; i < _codeBits.length; i++)
    {
        //string temp_str = "";
        var current_bitNumber = Math.ceil(Cesium.Math.logBase(_grids[i],2));
        temp_n = temp_n - current_bitNumber;
        var temp_str = GetBitsValueOfInt(n, temp_n, current_bitNumber);
        
        if (_grids[i] == 64)
        {
            _codeBits[i] = DecimalTo64System(parseInt(temp_str, 2));
        }
        else
        {
            _codeBits[i] = DecimalToArbitrarySystem(parseInt(temp_str, 2), _grids[i]);
        }
        if (_codeBits[i].Length != _codeCount[i])
        {
            _codeBits[i] = padLeft(_codeBits[i],_codeCount[i], '0');
        }
    }
    return arrayToString(_codeBits,l);//_codeBits.ArrayToString(l);
}
function arrayToString(arr,l){
    var result="";
    if(l>arr.length-1){
        l=arr.length-1;
    }
    for(var i=0;i<=l;i++){
        result+=arr[i];
    }
    return result;
}
function padLeft(str, totalWidth, paddingChar = ' ') {
    if (str.length >= totalWidth) {
        return str;
    }
    const paddingLength = totalWidth - str.length;
    return Array(paddingLength).fill(paddingChar).join('') + str;
}

/////////private function



export default BeiDouCode;
